Skip to content

Support reading skims from Parquet files, in addition to OMX - #1101

Open
jpn-- wants to merge 2 commits into
ActivitySim:mainfrom
driftlesslabs:main
Open

Support reading skims from Parquet files, in addition to OMX#1101
jpn-- wants to merge 2 commits into
ActivitySim:mainfrom
driftlesslabs:main

Conversation

@jpn--

@jpn-- jpn-- commented Aug 7, 2026

Copy link
Copy Markdown
Member

Closes #970

This pull request adds support for reading skim files in Parquet format in addition to the existing OMX format. The changes allow both dense and sparse Parquet files to be auto-detected and mixed with OMX files in the same workflow, with no changes required to existing settings other than using the .parquet or .pq file extension. The implementation includes updates to documentation, configuration, and the skim loading logic, ensuring compatibility with legacy workflows and Sharrow 2.16+ features.

Support for Parquet skim files:

  • Added logic to auto-detect and load skim files in Parquet format (with .parquet or .pq extensions) alongside OMX files. Parquet files can be dense or sparse and are supported by both legacy and Sharrow-based loaders. [1] [2] [3]
  • Updated documentation and configuration docstrings in network.py to describe Parquet skim file support and usage. [1] [2] [3]

Skim data loading and handling:

  • Refactored the skim dataset loading logic to merge data from multiple sources, handle time periods, and fill zeros for missing sparse OD pairs to maintain compatibility with legacy behavior.
  • Ensured that Parquet-backed datasets are properly handled when storing skims in shared memory, including closing file handles and supporting dask-backed data.

Codebase and API updates:

  • Added and documented new internal helpers for time period detection, masking, and zero-filling for Parquet files.
  • Updated the skim dictionary factory to cache Parquet file metadata and ensure consistent zone ID handling across mixed input files. [1] [2] [3]
  • Clarified and expanded docstrings to reflect support for both OMX and Parquet skim files throughout the codebase. [1] [2]

* Initial plan

* Add parquet skim reading support (dense row/col-major + sparse)

* Fix docstring typo found in code review

* Avoid duplicate array creation in dense layout detection

* Address review comments: searchsorted, table[col] indexing, caching, docstring

* Support Parquet skims in Sharrow runs

* Format Parquet skim tests

* Require Sharrow 2.16 and update uv lock

* Use released Sharrow from PyPI

* Fix Parquet skim loading across sparse and mixed sources

Normalize dense skims with nonascending zone IDs and zero-fill missing sparse OD pairs.
Preserve time-period pages when merging OMX and Parquet sources.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Jeff Newman <jeff@driftless.xyz>
@jpn--

jpn-- commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

@amsamimi I cannot formally make you a GitHub "reviewer" on this unless you accept the invitation to join the ActivitySim org, but since this addresses the issue you opened, you should definitely review it anyway 😉

@jpn--
jpn-- requested a review from amsamimi August 13, 2026 16:13
@jpn-- jpn-- added this to Phase 11 Aug 13, 2026
@jpn-- jpn-- moved this to Under Review in Phase 11 Aug 13, 2026

@amsamimi amsamimi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Sharrow-enabled smoke test completed successfully using the following configuration:

households_sample_size: 200
num_processes: 1
sharrow: true
models:
  - initialize_landuse
  - initialize_households
  - compute_accessibility

@jpn--

jpn-- commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Thanks for reviewing this @amsamimi.

At our recent engineering meeting, we also discussed that functional correctness is a necessary but not sufficient criteria for acceptance of new features; performance impacts are also relevant. While your smoke test is valuable, it would also be important to know if the new code is performing adequately. For this PR it may be possible to check that simply from the logs of the smoke test -- the main effect is at skim loading, which happens similarly for a full model run or this tiny piece of one. Can you look and see what the time needed to load parquet skims is, and compare against the equivalent OMX time on your same underlying data?

@amsamimi

amsamimi commented Aug 24, 2026

Copy link
Copy Markdown

@jpn-- @janzill @joecastiglione

I ran a full-skim test with a sample size of 10,000, using a single processor and Sharrow, under two scenarios: OMX and PARQUET. The memory/runtime profiles are attached, along with the corresponding log files.

Key Observations:

Metric PARQUET OMX
Peak Memory Usage 63 GB 22 GB
Total Runtime 23 min 28 min
initialize_landuse 2.4 min 7.1 min

OMX Version:
OMX_memory_profile
OMX_activitysim.log
OMX_mem.csv

PARQUET Version:
memory_profile
PARQUET_activitysim.log
PARQUET_mem.csv

@jpn--

jpn-- commented Aug 24, 2026

Copy link
Copy Markdown
Member Author

A few notes:

  • The tally of "Writing Skims to Shared Memory" at 21 sec vs 7 min is misleading; parquet is faster but not quite that much faster. I set about this PR with the singleminded instruction of "faster". This is achieved by reading parquet in parallel streams as fast as possible, but this analysis highlights that we are not piping those data streams directly to the final shared memory destination, we're just loading into whatever memory allocation makes it possible to do with maximum speed. So while it is technically correct that 21 seconds is the time it takes to get the skim data into shared memory, that is a RAM to RAM copy, and does not include read from disk or decompression. A more apples-to-apples comparison would include all the read from disk and decompress time, which is effectively the whole initialize_landuse step. Under that measure, we are looking at 2.5 minutes vs 7 minutes. Still a positive bump but not quite as large. And that 4.5 minutes difference is effectively the only difference between these two runs with respect to runtime.

  • It seems likely that with some careful planning about memory use, I should be able to find a solution were we can both have and eat the cake: faster loads, but directly into the shared memory space with no giant temporary array allocation. Doing this the right way may also deliver improved speed to OMX inputs as well. I already started working towards this in sharrow#87 but I am not done testing and evaluating whether that indeed works as intended.

  • I recommend we do not hold this PR until my theorized improvements can be proved out; users can decide if they have the RAM to pay the price to get this acceleration today, and then one day soon via another PR we might make it even better. I defer to @ActivitySim/product to review the current performance metrics and trade offs outlined above and decide.

@amsamimi

amsamimi commented Aug 24, 2026

Copy link
Copy Markdown

Thanks @jpn-- . I've updated the summary table to avoid any misunderstanding.

Another consideration is that initialize_landuse is not the memory bottleneck. While it has a local peak in memory usage, this does not have any practical consequences, at least for our use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

Support reading skims in Parquet format

3 participants